#ifndef GAMEENGINE_GRAPHICS_DISPLAY_LIST_H
#define GAMEENGINE_GRAPHICS_DISPLAY_LIST_H

#include <GameEngine/Graphics/graphics_settings.h>
#include <GameEngine/Graphics/graphic_resource.h>


#ifdef GAMEENGINE_NAMESPACES
namespace GameEngine {
#endif

//=================================================================================


//! Wrapper for OpenGL display lists
/*!
 *  A display list packs several OpenGL function calls into
 *  one single instruction, which can result in a significant
 *  speedup. Once packed, the set of function calls are all
 *  invoked with exactly the same parameters. This may not be
 *  suitable for situations where more flexibility is required
 *  (see the example below).
 *
 *  A display list packs all OpenGL function calls invoked between
 *  the begin_display_list() and the end_display_list() functions.
 *  An example of a typical use of this class would be:
 *  @code
 *  DisplayList dl; // this instance would typically be persistent (possibly a class member, or a pointer to dynamically allocated memory)
 *  dl.begin_display_list();
 *  // do graphic stuff...
 *  dl.end_display_list();
 *  @endcode
 *
 *  Please note that OpenGL calls are packed ONCE FOR ALL, regardless
 *  of whether some variables were changed after display list was
 *  packed. This class may therefore not be interesting for elements
 *  that are not static. For example, let's see the following code:
 *  @code
 *  // Drawing color: full green, no red nor blue
 *  float r = 0.0f, g = 1.0f, b = 0.0f;
 *  
 *  // Setup display list
 *  DisplayList dl;
 *  dl.begin_display_list();
 *  glColor3f(r,g,b); // Set color
 *  // Draw stuff... Things will get drawn in green
 *  dl.end_display_list();
 *  
 *  // Change drawing color: full red, no green nor blue
 *  r = 1.0f, g = 0.0f, b = 0.0f;
 *  glColor3f(r,g,b); // Set color
 *  
 *  // Draw the scene
 *  dl.draw();
 *  @endcode
 *  In the example above, the scene will ALWAYS be drawn in green, because
 *  when the display list was packed, drawing color was set to green IN THE
 *  DISPLAY LIST. One way to get around this issue is to separate the scene
 *  into static components (stored in the display list) and dynamic components
 *  (outside of the display list). Let's go back to the example where we want
 *  to dynamically change the color. A correct version would be:
 *  @code
 *  // Drawing color: full green, no red nor blue
 *  float r = 0.0f, g = 1.0f, b = 0.0f;
 *  glColor3f(r,g,b); // Set color
 *  
 *  // Setup display list
 *  DisplayList dl;
 *  dl.begin_display_list();
 *  // Draw stuff...
 *  dl.end_display_list();
 *  
 *  // Draw the scene - things will get drawn in green
 *  dl.draw();
 *  
 *  // Change drawing color: full red, no green nor blue
 *  r = 1.0f, g = 0.0f, b = 0.0f;
 *  glColor3f(r,g,b); // Set color
 *  
 *  // Draw the scene - things will get drawn in red
 *  dl.draw();
 *  @endcode
 *
 *  Still, if most of the elements you are drawing have to be dynamic, you
 *  should consider using other strategies to speed up the rendering.
 *
 *  The display lists are handled as resources, which allows them to be quickly
 *  and safely copied / deleted.
 *
 @note This class must always be manipulated AFTER a valid OpenGL context has been created. If
       no OpenGL context is available, any call to any function or constructor of this class
	   will result in an application crash.
 */
class _Graphics_decl DisplayList : public GraphicResource {
	GAMEENGINE_DECLARE_RTTI_PARENT(DisplayList,GraphicResource)
	//! The resource manager class is friend of the display list class because it must be able to access its ID and context
	friend class ResourceManager<ID,CONTEXTID>;

public:
	DisplayList();
	DisplayList(const DisplayList& rhs);
	virtual ~DisplayList();
	DisplayList& operator=(const DisplayList& rhs);

	void begin_display_list();
	void end_display_list();

	void draw() const;

	void clear();
	bool initialized() const;

private:
	void clean_id();
	void create_id();

	virtual void destroy_resource() const;
	virtual CONTEXTID context() const;
	virtual ID reference() const;

private:
	ID id_;
};

#ifdef GAMEENGINE_NAMESPACES
} // namespace GameEngine
#endif

#endif
